package com.ksyun.campus.metaserver.controller;

import com.ksyun.campus.metaserver.domain.dto.ApiResponse;
import com.ksyun.campus.metaserver.services.ReplicaAllocationMonitor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * 副本分配监控REST API控制器
 * 提供副本分配统计信息和负载均衡监控接口
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/admin/replica-monitor")
public class ReplicaMonitorController {
    
    @Autowired
    private ReplicaAllocationMonitor allocationMonitor;
    
    /**
     * 获取副本分配统计信息
     * 
     * @return 包含详细统计信息的响应
     */
    @GetMapping("/stats")
    public ApiResponse<Map<String, Object>> getReplicaStats() {
        try {
            Map<String, Object> stats = allocationMonitor.getDetailedStats();
            return ApiResponse.success(stats);
        } catch (Exception e) {
            log.error("Error getting replica statistics", e);
            return ApiResponse.error("Failed to get replica statistics: " + e.getMessage());
        }
    }
    
    /**
     * 获取负载均衡状态
     * 
     * @param threshold 标准差阈值，默认为5.0
     * @return 负载均衡状态信息
     */
    @GetMapping("/load-balance")
    public ApiResponse<Map<String, Object>> getLoadBalanceStatus(
            @RequestParam(defaultValue = "5.0") double threshold) {
        try {
            ReplicaAllocationMonitor.LoadBalanceStats stats = allocationMonitor.getLoadBalanceStats();
            boolean isBalanced = allocationMonitor.isLoadBalanced(threshold);
            
            Map<String, Object> response = Map.of(
                    "isLoadBalanced", isBalanced,
                    "threshold", threshold,
                    "selectionStdDev", stats.getSelectionStdDev(),
                    "primaryStdDev", stats.getPrimaryStdDev(),
                    "avgSelectionsPerServer", stats.getAvgSelectionsPerServer(),
                    "maxMinSelectionRatio", stats.getMaxMinSelectionRatio(),
                    "recommendation", isBalanced ? 
                            "负载均衡良好" : 
                            "建议检查DataServer容量分布或调整分配策略"
            );
            
            return ApiResponse.success(response);
        } catch (Exception e) {
            log.error("Error getting load balance status", e);
            return ApiResponse.error("Failed to get load balance status: " + e.getMessage());
        }
    }
    
    /**
     * 重置监控统计信息
     * 
     * @return 操作结果
     */
    @PostMapping("/reset")
    public ApiResponse<Void> resetMonitorStats() {
        try {
            allocationMonitor.reset();
            log.info("Replica allocation monitor statistics reset by admin request");
            return ApiResponse.success();
        } catch (Exception e) {
            log.error("Error resetting monitor statistics", e);
            return ApiResponse.error("Failed to reset statistics: " + e.getMessage());
        }
    }
    
    /**
     * 获取副本分配策略信息
     * 
     * @return 当前使用的分配策略信息
     */
    @GetMapping("/strategy-info")
    public ApiResponse<Map<String, Object>> getStrategyInfo() {
        try {
            Map<String, Object> strategyInfo = Map.of(
                    "strategy", "轮询 + 容量权重混合策略",
                    "description", "首先根据剩余容量计算权重，然后结合轮询机制选择副本位置",
                    "features", Map.of(
                            "capacityWeighted", "根据剩余容量分配权重，容量大的节点优先选择",
                            "roundRobin", "使用轮询计数器确保负载均衡",
                            "uniqueReplicas", "严格保证副本不会分配到同一个DataServer",
                            "primarySelection", "第一个副本总是选择权重最高的节点作为PRIMARY"
                    ),
                    "benefits", Map.of(
                            "loadBalance", "避免副本总是分配到相同节点",
                            "capacityAware", "优先使用剩余容量大的节点",
                            "faultTolerance", "确保三副本分布在不同的DataServer上",
                            "performance", "PRIMARY副本总是在容量最大的节点上"
                    )
            );
            
            return ApiResponse.success(strategyInfo);
        } catch (Exception e) {
            log.error("Error getting strategy info", e);
            return ApiResponse.error("Failed to get strategy info: " + e.getMessage());
        }
    }
}
